// main.cpp, ELEC254, Group14, Magic Music Matrix
// Hilda, ee_hqxaa
// version1, 9,July, 2008
// version1.2, 15,July, 2008
// version1.3, 22 July 2008
// version1.4, 4 Aug 2008
//http://blog.163.com/waft_xu/blog/static/43815294200803194611656/
//-------------------------------------------------------
//macros
//-------------------------------------------------------
#define F_CPU 7372800UL

#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>

#include "SD.h"
#include "FAT.h"
#include "VS.h"
#include "LED.h"
#include "LCD.h"

// define data type
#define uint8 unsigned char
#define uint16 unsigned int
#define uint32 unsigned long


// we put the songs in SD's root directory temporarily
#define PATH (unsigned char *) ("\\")

//define pins
#define PLAYM			_BV(PG0)
#define PREV			_BV(PG1)
#define NEXT			_BV(PG2)
#define POLL			PING

#define SPI_SCK		1
#define SPI_MOSI	2
#define SPI_MISO	3
#define SPI_PORT		PORTB
#define SPI_DDR			DDRB


extern unsigned char lib[];
extern unsigned char tamama[];
extern unsigned char  FAT32_Enable;
extern unsigned char *cnt;
extern unsigned int SectorsPerClust;
extern unsigned long FirstFATSector;
extern unsigned long FirstDirSector;
extern unsigned long FirstDataSector;
extern uint16 data[];					// to sample music by timer interrupt
extern uint8 *cnt;



#define DEBUGLED1_CON() DDRA|=_BV(PA0)
#define DEBUGLED1_ON()  PORTA|=_BV(PA0)
#define DEBUGLED1_OFF() PORTA&=~_BV(PA0)

#define DEBUGLED2_CON() DDRA|=_BV(PA1)
#define DEBUGLED2_ON()  PORTA|=_BV(PA1)
#define DEBUGLED2_OFF() PORTA&=~_BV(PA1)

#define DEBUGLED3_CON() DDRA|=_BV(PA2)
#define DEBUGLED3_ON()  PORTA|=_BV(PA2)
#define DEBUGLED3_OFF() PORTA&=~_BV(PA2)

#define DEBUGLED4_CON() DDRA|=_BV(PA3)
#define DEBUGLED4_ON()  PORTA|=_BV(PA3)
#define DEBUGLED4_OFF() PORTA&=~_BV(PA3)

#define DEBUGLED5_CON() DDRA|=_BV(PA4)
#define DEBUGLED5_ON()  PORTA|=_BV(PA4)
#define DEBUGLED5_OFF() PORTA&=~_BV(PA4)

#define DEBUGLED6_CON() DDRA|=_BV(PA5)
#define DEBUGLED6_ON()  PORTA|=_BV(PA5)
#define DEBUGLED6_OFF() PORTA&=~_BV(PA5)

#define DEBUGLED7_CON() DDRA|=_BV(PA6)
#define DEBUGLED7_ON()  PORTA|=_BV(PA6)
#define DEBUGLED7_OFF() PORTA&=~_BV(PA6)

#define DEBUGLED8_CON() DDRA|=_BV(PA7)
#define DEBUGLED8_ON()  PORTA|=_BV(PA7)
#define DEBUGLED8_OFF() PORTA&=~_BV(PA7)




//-------------------------------------------------------
//aclaim data structure
//-------------------------------------------------------

uint8 num_songs;						// total number of songs
uint8 whichsong;						// the song playing
uint8 file_type = 1;					// we support only mp3 file type now, maybe we can add wma, and midi later
uint8 ctrl;

struct FileInfoStruct FileInfo;
struct direntry MusicInfo;








//-------------------------------------------------------
// my own functions
//-------------------------------------------------------

void PORT_init_all(){
	//for contrl prev, next, pause
	DDRG &= 0x1f;
	//for spi
	DDRB |=_BV(0)|_BV(1)|_BV(2);
	//for led
	DDRA = 0xff;
	//for lcd
	LCD_init();
	//for adc
	DDRF = 0xFE;
	PORTF = 0xFE;
}


void delay500ms(){
	unsigned char cnt;
	for(cnt = 0; cnt< 30; cnt++){
		_delay_ms(20);
	}
}

void timer1_ini(void){
	TCNT1H=0x00;
	TCNT1L=0x00;
	TCCR1B=0x01;									// frequency the same as machine cycle
	ICR1H=0xff;
	ICR1L=0xff;
}

/*

void timer2_ini(){
	TCNT2H=0x00;
	TCNT2L=0x00;
	TCCR2B=0x01;									// frequency the same as machine cycle
	ICR2H=0xff;
	ICR2L=0xff;
}

*/


unsigned char check_ctrl(void){

	//=====================
	//===polling key=======
	//=====================
	if(!(POLL&PLAYM))									// key PLAY/PAUSE is pressed to 1
	{
		_delay_ms(5);
		if(!(POLL&PLAYM)){
			while(!(POLL&PLAYM));						// wait the key to release
			return 1;
		}
	}
	else if(!(POLL&NEXT)){
		_delay_ms(5);
		if(!(POLL&NEXT)){
			while(!(POLL&NEXT));
			if( whichsong > num_songs)whichsong = 1; else whichsong++;
			return 2;
		}
	}
	else if(!(POLL&PREV)){
		_delay_ms(5);
		if(!(POLL&PREV)){
			while(!(PIND&PREV));
			if(whichsong==1)  whichsong = num_songs; else whichsong--;
			return 2;
		}
	}
	return 0;
}



void idle(void){
	while(1){
	//loop light up one led
	//check poll every light up
		ctrl = check_ctrl();
		if(ctrl){
			disp_Char('P',lib,5,0);
			disp_Char('L',lib,5,1);
			disp_Char('A',lib,5,2);
			disp_Char('Y',lib,5,3);
			disp_Char('@',lib,5,4);
			//disp_Char(ctrl + 0x30, lib, 4,4);
			disp_Char(' ',lib,4,0);
			disp_Char(' ',lib,4,1);
			disp_Char(' ',lib,4,2);
			disp_Char(' ',lib,4,3);
			disp_Char(' ',lib,4,4);
			break;
		}
		disp_Char('I',lib,4,0);
		disp_Char('D',lib,4,1);
		disp_Char('L',lib,4,2);
		disp_Char('E',lib,4,3);
		disp_Char('@',lib,4,4);
		//disp_Char(ctrl + 0x30, lib, 3,4);
		disp_Char(' ',lib,5,0);
		disp_Char(' ',lib,5,1);
		disp_Char(' ',lib,5,2);
		disp_Char(' ',lib,5,3);
		disp_Char(' ',lib,5,4);
	}
}


// idle mode: polling the keys, display random led
// play mode: play music, do spec analyse, display matrix
void play(void){

	//=============variable define
		uint16 keylen;			//for key processing
		uint8 whichsong=0;				//play the fist songs by default

		uint16 count;			//data counting
		uint8 i;				//loop variable
		uint16 j;				//loop variable


		uint32 p;									//cluster
		uint32 totalsect;							//total sector of a file
		uint16 leftbytes;							//cotain the left bytes number of a file for the last cluster read
		uint8 *buffer;								//data buffer
		uint32 sector;								//record the current sector to judge the end sector


		for(i=0;i<10;i++)
			disp_Char('*',lib,0,i);

		disp_Char('L',lib,1,0);
		disp_Char('e',lib,1,1);
		disp_Char('t',lib,1,2);
		disp_Char('\'',lib,1,3);
		disp_Char('s',lib,1,4);
		disp_Char(' ',lib,1,5);
		disp_Char('R',lib,1,6);
		disp_Char('O',lib,1,7);
		disp_Char('C',lib,1,8);
		disp_Char('K',lib,1,9);

		for(i=0;i<10;i++)
			disp_Char('*',lib,2,i);



		uint8 flag;					//flag of entering idle mode
//		uint16 vol=DefaultVolume;	//default volume
//		uint8 mode=DefaultIdle;   	//stay idle


		timer1_ini();			//initialize the timer
//		timer2_ini();
//		clear_track();

		if(num_songs==0)return;	//if no music file return




	//===============play

next:												//label to goto when after one song or receive control

			whichsong++;
			if(whichsong == num_songs)
			{whichsong = 1;}




		//---------------------VS initialize----------------------------------
		VS_XCS_H();
		VS_XDCS_L();

		count = 0;
		while(count<2048)					// not for MID format
		{
			if((VS_PIN & _BV(VS_DREQ))!=0){
				for(j=0;j<32;j++){
					VS_WriteDAT(0x00);				//issue 0 seq and wait for DREQ
					count++;
				}
				if(count == 2047)break;
			}
		}

		VS_SoftReset();
	//---------------------------------------------------------------------



		//-------------------find the song and its size from SD,FAT32----------


		search(PATH,&MusicInfo,&whichsong,&file_type);
		//=============================
		// LCD display music infomation
		//=============================
		disp_Char(whichsong+0x30,lib,6,0);
		disp_Char('.',lib,6,1);
		for(i=0; i<8; i++){
			disp_Char(MusicInfo.deName[i],lib,6,i+2);
		}

		p = MusicInfo.deStartCluster + (((uint32)MusicInfo.deHighClust)<<16);	// it is to find the first cluster of the file
		totalsect = MusicInfo.deFileSize/512;									// song's total sectors
		leftbytes = MusicInfo.deFileSize%512;									// song's last maybe incomplete sector
		i = 0;
		sector = 0;


		while(1){
			buffer = malloc(512);				// 512 bytes / sector
			keylen = 0;
			//=====================
			//=read a cluster at p=
			//=====================

			for(i=0; i<SectorsPerClust; i++){			// read sectors in a cluster

				//=================
				//==read a sector==
				//=================

				FAT_LoadPartCluster(p,i,buffer);	// read one sector to buffer
				count = 0;

				//====================
				//===write 512bytes====
				//====================
				while(count<512){					// try to send one sector every 32 bytes to VS
					//====================
					//===write 32bytes====
					//====================
					if((VS_PIN & _BV(VS_DREQ))!=0)				// wait for DREQ and write 32bytes to VS's buffer
					{
						for(j=0;j<32;j++){
							VS_WriteDAT(buffer[count]); count++;
						}
						if(sector == totalsect && count>=leftbytes){		//file ends here
							i = SectorsPerClust; break;					//break from sector, finish this cluster
						}
						if(count == 511){break;}
					}//end if of 32bytes
				}//end of 512 bytes = 1 sector
				sector++;
			}//end of read one cluster
			i = 0;
			free(buffer);


			//==================every other cluster, do spectrum analyse
			//==================every other cluster, polling control key
			ctrl = check_ctrl();
			if(ctrl == 1){
				idle();
			}if(ctrl == 2){
				goto next;
			}

			//==================================================
			//==find next cluster to goto, while(1), continue===
			//==================================================

			p = FAT_NextCluster(p);	//read next cluster
			if((p==0x0fffffff)||(p==0x0ffffff8)||((FAT32_Enable==0)&&(p == 0xffff)))
            {// no more clusters to read
				if(whichsong > num_songs) whichsong = 0;
				goto next;
			}
		}//end of while(1) continue play next song


}












//---------------------------------------------------------
// main.c
//---------------------------------------------------------

int main(void)
{
	//=====initialization and check component interface

	PORT_init_all();

	DEBUGLED1_CON();					// initialize debug led
	DEBUGLED1_OFF();
	DEBUGLED2_CON();
	DEBUGLED2_OFF();
	DEBUGLED3_CON();					// initialize debug led
	DEBUGLED3_OFF();
	DEBUGLED4_CON();
	DEBUGLED4_OFF();
	DEBUGLED5_CON();					// initialize debug led
	DEBUGLED5_OFF();
	DEBUGLED6_CON();
	DEBUGLED6_OFF();
	DEBUGLED7_CON();					// initialize debug led
	DEBUGLED7_OFF();
	DEBUGLED8_CON();
	DEBUGLED8_OFF();

	*cnt = 0;


	UCSR0B = 0;
	UBRR0L = 3;
	UBRR0H = 0x00;							// Baud Rate 115200
	UCSR0A = 0;
	UCSR0C = (1<<UCSZ01)|(1<<UCSZ00);
	UCSR0B = (1<<TXEN0);					// 8 bit char


	delay500ms();

	cls();

	spi_init();

	CS_1_L();
	CS_2_H();
	disp_pic(tamama);
	CS_1_H();
	CS_2_L();


	if ( VS_ini()){						// VS1003 initialize, if failed,light up debug1 and stop
		while(1){
			DEBUGLED1_ON();
			delay500ms();
			DEBUGLED1_OFF();
			delay500ms();
		}
	}else{
		disp_Char('V',lib,0,0);
		disp_Char('S',lib,0,1);
		disp_Char('i',lib,0,2);
		disp_Char('n',lib,0,3);
		disp_Char('i',lib,0,4);
	}



	SPCR =  _BV(SPE)|_BV(MSTR);
	SPSR |= _BV(SPI2X);





	SD_Init();
	uint8 SD_try = 0x00;				// since SD is insert by user, we need tocheck it more patiently
	while ( SD_Reset()){				// SD initialize, if failed, light up debug2 and stop
		SD_try++;
		if ( SD_try > 30 )
		while(1){
			DEBUGLED2_ON();
			delay500ms();
			DEBUGLED2_OFF();
			delay500ms();
		}
	}
	disp_Char('S',lib,1,0);
	disp_Char('D',lib,1,1);
	disp_Char('i',lib,1,2);
	disp_Char('n',lib,1,3);
	disp_Char('i',lib,1,4);





	if(FAT_Init()){
		while(1){
			DEBUGLED3_ON();
			delay500ms();
			DEBUGLED3_OFF();
			delay500ms();
		}
	}else{
		disp_Char('F',lib,2,0);
		disp_Char('A',lib,2,1);
		disp_Char('T',lib,2,2);
		disp_Char('i',lib,2,3);
		disp_Char('n',lib,2,4);
		disp_Char('i',lib,2,5);
	}





	// default enter idle mode and light LED
	// polling to check pin of PAUSE/PLAY
	idle();
	num_songs = 6;
	whichsong = 0;

	//=======normal working phase

	search(PATH,&MusicInfo,&whichsong,&file_type);  // search songs in root directory

	play();								// try to be nice, music +spec_led


	//display in LCD "MUSIC is the bread of life~"

	return 0;
}


